This document describes the format of the resources contained in version 5.0 of a ResCompare self╨applying patch.
To edit a patch file, use ResEdit with the supplied ╥Patch 5.0 templates╙ ResEdit document. Simply open this file in ResEdit, along with a patch file, to provide editing templates for the patch resources.
'ZVER' resource
A self╨applying patch contains patches for any number of versions of any number of files. There is a 'ZVER' resource for each file that is to be updated by the patch. The resource name is the prompt to be used when asking the user for this file.
The 'ZVER' resources are numbered starting at 128, in increments of 1.
The 'ZVER' resource contains some header information describing the file to be patched, followed by a list of valid versions. Here is the complete structure of the 'ZVER' resource:
/* Information maintained for each file version */
struct {
ZVerFlags flags;
OSType fdType, fdCreator;
MasterOption masterOpt;
UpdateOption updateOpt;
Size finalRsrcForkSize;
unsigned long finalCreationDate, finalModificationDate;
Str31 renameToName;
Str31 saveAsName;
short numVersions;
struct {
unsigned long fromVersion;
unsigned long toVersion;
short zapListID;
long totalMunges;
} theZapRef[];
} ZapVersion;
flags
A bitmask of flags that can be OR-ed together, currently unused.
fdType, fdCreator
These fields are the type and creator of the target file. Only files matching this criteria are listed in the GetFile dialog. You can remove the creator criteria by setting the creator to 0. To provide a more comprehensive list of types and creators, add a corresponding 'ZTC#' resource, which is described below.
masterOpt
One of the following options, which define what is done with the master file after patching.
Replace the master file with the update file. Invalid if combined with kMasterLeaveOption, above.
kUpdateSaveAsOption
Prompt the user to save the update file, using the suggested name in saveAsName, below.
kUpdateExchangeOption
Exchange the master file with the update file, preserving its file ID.
finalRsrcForkSize
Final size in bytes of the file╒s resource fork after patching. This field is used to determine if disk space is available to perform the patch.
finalCreationDate, finalModificationDate
Creation and modification date of the final patch in this version list. Used to set the update file╒s creation and modification date after patching.
renameToName
If the master file╒s disposition uses kMasterRenameMask, it is renamed to this name. The renameToName can contain the substituters ^FILE, which is replaced with the target file╒s name, and ^VERS, which is replaced with the target file╒s version. The default renameToName is ╥^FILE ^VERS backup╙. If, after substitution, a file by this name already exists, a unique name is chosen by appending a number to the name.
saveAsName
If the update file╒s disposition is kUpdateSaveAsOption, this field is used as the default name for the update file.
numVersions
The number of version records to follow.
theZapRef[]
A list of version records. This list is searched to locate a starting point for applying the patch. The version records use the following format:
fromVersion
The 4╨byte version code this patch converts from.
toVersion
The 4╨byte version code this patch converts to.
zapListID
The resource ID of the 'ZAP#' resource for this patch.
totalMunges
The total of all the numMunges fields in the corresponding 'ZAP#'. This info is used to calculate the goal for the status thermometer.
'ZFIL' resource
This is an optional resource you can add to a patch once it╒s built to automatically identify a file╒s location without prompting the user. This is useful when the patch is for a control panel or extension, as the file may be in a folder locatable by FindFolder. The resource ID of the 'ZFIL' resource must match the 'ZVER' resource ID. The file must also have the same fdType and fdCreator as listed in the 'ZVER' or 'ZTC#' resource.
#define kAnyRegion (-1)
// Will have the same ID as its corresponding ZVER
typedef struct {
OSType folderType;
short numFileLocs;
struct {
short region;
Str31 name;
} theFileLoc[];
} ZapFileLocList;
folderType
A four╨character type code recognized by FindFolder. The patch will search this folder on the system disk.
Set the folderType to a longword binary 0 (zero) to search for the target file by its full or partial pathname. Partial pathnames are resolved relative to the default volume and directory. The initial default volume and directory is the root directory of the system disk. To set folderType to zero with ResEdit, open an existing 'ZFIL' resource with the option key held down and change the first four bytes using the hex editor.
Set the folderType to a longword binary 1 to have the same effect as 0, but to reset the default volume and directory to its initial location first.
numFileLocs
The number of possible file names to follow.
theFileLoc[]
A list of file names. A list is used so multiple international spellings can be included. Each file name is accompanied by its region code, and the name corresponding to the current region of the system script is used.
region
The region code that identifies this name, or the constant kAnyRegion (╨1) to match any region. Region codes are listed in Inside Macintosh, Volume VI, p. 14╨84, table 14╨10, in the <Packages.h> header file, and in ResEdit╒s ╥Country Code╙ pop╨up menu located in the 'vers' editor.
name
The file name to look for, localized for this language.
The patch will scan the file loc list looking for a region code that matches the region of the system script, or for the wildcard value kAnyRegion (╨1).
If a file name cannot be found for the current region, the folder cannot be found, the requested file does not exist, or the file exists but its type and creator don╒t match, the patch will prompt the user for the file. If the patch was able to determine a file name, it places the name as dialog substitution parameter ╥^0╙, so you can use a prompt string of ╥Where is ^0?╙ to include the localized name in the prompt.
You can also provide a partial pathname, such as ╥:MyApp Folder:MyApp╙ to search a folder at the root level of the system disk named ╥MyApp Folder╙ for the ╥MyApp╙╩application.
'ZTC#' resource
This is an optional resource you can add to a patch once it╒s built to provide a comprehensive list of type/creator pairs that define a target file. You can use kTypeCreatorWildcard ('****') for either the type or the creator. The resource ID of the 'ZTC#' resource must match the 'ZVER' resource ID. The types and creators specified here override any type or creator given in the 'ZVER' resource.
#define kTypeCreatorWildcard '****'
// Will have the same ID as its corresponding ZVER
typedef struct {
short numPairs;
struct {
OSType fdType, fdCreator;
} pair[];
} TypeCreatorList;
numPairs
The number of type/creator pairs to follow.
fdType
A four╨character file type code. The patch╒s GetFile dialog will only show files with this type and the creator specified below. Use '****' to match any type.
fdCreator
A four╨character file creator code. The patch╒s GetFile dialog will only show files with this creator and the type specified above. Use '****' to match any creator.
'ZAP#' resource
The 'ZAP#' resource contains a list of all resources that need to be patched, for a given version transition of a given file. The 'ZVER' contains a list of 'ZAP#' resource IDs. The resource name of the 'ZAP#' will be the name of the master file from which the patch was created. This name is not used by the patch and is for reference purposes only. 'ZAP#' resources are numbered starting at 1000 and incremented by 1000.
The resource IDs of the 'ZAP ' resource that holds the munge data for patching each resource start with the 'ZAP#' and are incremented by 1. There is also a corresponding 'ZIS#' or 'ZIL#' resource with the same ID, based on the setting of the shortMunges flag.
struct {
short numZaps;
// Information maintained for each resource to be zapped
struct {
ZapFlags flags;
ResType resType;
short resID;
short newResAttrs;
Size newResSize;
// These fields are used to verify the resources
long newResContentsChecksum;
short resAttrs;
Size resSize;
long resContentsChecksum;
Str255 resName;
} theZap[];
} ZapList;
numZaps
The number of zap records to follow. There is one for each resource to be patched.
flags
A bitmask of flags that can be OR-ed together, with the following definitions:
// What parts of resource to skip during verification
dontVerifyAttrs = 0x00010000,
dontVerifySize = 0x00020000,
dontVerifyName = 0x00040000,
dontVerifyContents = 0x00080000,
dontVerifyNewContents = 0x00100000
} ZapFlags;
shortMunges
If set, this flag indicates that both the master and update resource are less than 32K, and 16╨bit integers can be used for their offsets and lengths. Otherwise, 32╨bit integers must be used. When this flag is set, the zap instruction list is stored in a 'ZIS#' resource; otherwise, it is stored in a 'ZIL#' resource. Most resources are less than 32K, while most data forks of PowerPC applications are much larger.
needNotVerify
If set, this flag indicates that, should resource verification fail, the patch application should perform the operation anyway in certain cases. If adding a resource that already exists, no change is made. If deleting a resource, the resource can be of any length if it exists. If changing a resource, no change is made.
verifyFailed
This flag is used internally during the patching process and should always be set to 0 within the patch.
alwaysUpdate
If set, this flag indicates that, should resource verification fail, the patch application should perform the operation anyway in all cases. If adding a resource that already exists, the entire resource is replaced. If deleting a resource, the resource can be of any length if it exists. If changing a resource, the resource╒s size is adjusted to its size in the master file and the patch is applied anyway.
The needNotVerify bit must be set for alwaysUpdate to take effect.
zapStatusMaster, zapStatusUpdate
These flags indicate whether the target resource should appear in the master or update file, respectively. The various combinations of them are OR-ed together to indicate that the resource should be deleted, added, or changed.
If set, these flags indicate that the patcher should skip the check of the indicated parts of the master resource when determining whether the master file is a valid target. Resource existance is always verified, but can be controlled with the needNotVerify and alwaysUpdate bits.
resType, resID
This is the resource type and ID of the resource to be patched.
newResAttrs
These are the resource attributes to be applied to the update resource, or 0 if the resource is to be deleted.
newResSize
This is the final size of the update resource, or 0 if the resource is to be deleted.
newResContentsChecksum
This is a checksum of the data in the update resource, or 0 if the resource is to be deleted. After patching, the resource is checksummed and its value must match, unless the dontVerifyNewContents bit is set.
resAttrs
These are the expected resource attributes of the master resource, or 0 if the resource is to be added. These attributes must match during resource verification, unless the dontVerifyAttrs bit is set.
The special resource attribute 0x0100 means this ╥resource╙ is really the data fork.
resSize
This is the expected size of the master resource. If the resource is being added, this size will be 0. The sizes must match during resource verification, unless the dontVerifySize bit is set.
resContentsChecksum
This is a checksum of the data in the master resource, or 0 if the resource is being added. During resource verification, the master resource is checksummed and its value must match, unless the dontVerifyContents bit is set.
resName
This is the expected name of the master resource, or the empty string if the resource is to be added. The names must match during resource verification, unless the dontVerifyName bit is set.
Note that the final name of the update resource is stored as the resource name of its munge data ('ZAP ') resource (described below).
'ZIL#' and 'ZIS#' resources
The 'ZIL#' and 'ZIS#' resources contain a list of munges, or patch operations to be performed on a resource. Their formats are identical, except the 'ZIL#' uses 32╨bit offsets and lengths, while the 'ZIS#' uses 16╨bit offsets and lengths. 'ZIS#' is typically used, except for extremely large (>32K) resources. 'ZIL#' is typically used for the data fork.
The munges are divided into several lists: the additive munge list, the same-sized munge list, and the different-sized munge list. The different-sized munge list contains all the munges for which the master length is not the same as the update length. Note that a master length of 0 indicates data is being inserted, and an update length of 0 indicates data is being deleted.
A much more common occurrance is that the two lengths are the same. These munges are put into their own list, the same-sized munge list. This list is sorted into several groups, one for each unique common size.
Of all the same-sized munges, those of length 1 are treated specially. For them, the signed difference between the update and the master byte is computed and if this difference occurs more than once, that munge is placed in the additive munge list. The delta value of the munge data is only stored once in the munge data.
Munges are applied in the order they╒re encountered in the munge instruction list.
/* 'ZIL#' */
typedef struct {
long masterOffset; // Offset into master data at which to apply munge
} AddLMunge, *AddLMungePtr;
typedef struct {
long numAddMunges; // Number of additive munges to follow
AddLMunge theAddMunge[]; // List of additive munges
} AddLMungeGroup, *AddLMungeGroupPtr;
typedef struct {
long numAddMungeGroups; // Number of additive munge groups
AddLMungeGroup theAddMungeGroup[]; // List of additive munge groups
} AddLMungeList, *AddLMungeListPtr;
typedef struct {
long masterOffset; // Offset into master data at which to apply munge
} SSLMunge, *SSLMungePtr;
typedef struct {
long commonLength; // Common length for this group
long numSSMunges; // Number of same-sized munges to follow
SSLMunge theSSMunge[]; // List of same-sized munges
} SSLMungeGroup, *SSLMungeGroupPtr;
typedef struct {
long numSSMungeGroups; // Number of same-sized munge groups
SSLMungeGroup theSSMungeGroup[]; // List of same-sized munge groups
} SSLMungeList, *SSLMungeListPtr;
typedef struct {
long masterOffset; // Offset into master data at which to apply munge
long masterLength; // Length of master data to delete
long updateLength; // Length of update data to insert
} DSLMunge, *DSLMungePtr;
typedef struct {
long numDSMunges; // Number of different-sized munges
DSLMunge theDSMunge[]; // List of different-sized munges
} DSLMungeList, *DSLMungeListPtr;
typedef struct {
AddLMungeList theAddMungeList; // Additive munge list
// SSLMungeList theSSMungeList; // Same-sized munge list
// DSLMungeList theDSMungeList; // Different-sized munge list
The 'ZAP ' resource (note trailing space) contain the actualmunge data that╒s used for insert or replace patch operations. The data is arranged in the order specified by the munge instructions.
The updated resource gets its new resource name from the resource name of the 'ZAP ' resource. Every resource that is not being deleted gets a 'ZAP '/'ZIx#' resource pair, even if the only change is to the resource╒s attributes or name.
/* ZAP resource--the munge data to insert/replace */
#define ZapMungeType 'ZAP '
To contact me
I hope you enjoy ResCompare. If you like it and find it useful, let me hear from you. If you have any suggestions, questions, or bug reports, send me e╨mail at hecht@vnet.net.